package com.rec.smile.rpc.provider;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.rec.smile.rpc.api.RpcRequest;
import com.rec.smile.rpc.api.RpcResponse;
import com.rec.smile.rpc.api.RpcService;
import com.rec.smile.rpc.api.codec.RpcDecoder;
import com.rec.smile.rpc.api.codec.RpcEncoder;
import com.rec.smile.rpc.provider.codec.RpcHandler;
import com.rec.smile.rpc.registry.ServiceRegistryApi;

/**
 * Hello world!
 *
 */
public class RpcServer implements ApplicationContextAware, InitializingBean
{
	
	private static final Logger LOGGER = LoggerFactory.getLogger(RpcServer.class);
	
	private String serverAddress;
	
	private Map<String, Object> handlerMap = new HashMap<String, Object>();
	
	private ServiceRegistryApi serviceRegistryApi;

    public RpcServer(String serverAddress, ServiceRegistryApi serviceRegistryApi) {
		super();
		this.serverAddress = serverAddress;
		this.serviceRegistryApi = serviceRegistryApi;
	}
    
    
	@Override
	public void afterPropertiesSet() throws Exception {
	     EventLoopGroup bossGroup = new NioEventLoopGroup();
	        EventLoopGroup workerGroup = new NioEventLoopGroup();
	        try {
	            ServerBootstrap bootstrap = new ServerBootstrap();
	            bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
	                .childHandler(new ChannelInitializer<SocketChannel>() {
	                    @Override
	                    public void initChannel(SocketChannel channel) throws Exception {
	                        channel.pipeline()
	                            .addLast(new RpcDecoder(RpcRequest.class)) // 将 RPC 请求进行解码（为了处理请求）
	                            .addLast(new RpcEncoder(RpcResponse.class)) // 将 RPC 响应进行编码（为了返回响应）
	                            .addLast(new RpcHandler(handlerMap)); // 处理 RPC 请求
	                    }
	                })
	                .option(ChannelOption.SO_BACKLOG, 128)
	                .childOption(ChannelOption.SO_KEEPALIVE, true);
	            String[] array = serverAddress.split(":");
	            ChannelFuture channelFuture = bootstrap.bind(array[0], Integer.parseInt(array[1])).sync();
	            LOGGER.info("server start on port {}", Integer.parseInt(array[1]));
//	            if(serviceRegistry != null){
//	            	//serviceRegistry.register(serverAddress);
//	            }
	            serviceRegistryApi.register(serverAddress);
	            channelFuture.channel().closeFuture().sync();
	        }catch(Exception e){
	        	e.printStackTrace();
	        }finally{
	        	workerGroup.shutdownGracefully();
	            bossGroup.shutdownGracefully();
	        }
	}

	@Override
	public void setApplicationContext(ApplicationContext ctx)
			throws BeansException {
		Map<String, Object> beansWithAnnotation = ctx.getBeansWithAnnotation(RpcService.class);
		if(MapUtils.isNotEmpty(beansWithAnnotation)){
			for (Object serviceBean : beansWithAnnotation.values()) {
				String interfaceName = serviceBean.getClass().getAnnotation(RpcService.class).value().getName();
				handlerMap.put(interfaceName, serviceBean);
			}
		}
		
	}
}
